using System;
using System.Data;
using System.Reflection;
using NUnit.Framework;
using ODX.Core;
using ODX.LazyUnitTester;

namespace Events
{
    [Table]
    public abstract class Account : Entity
    {
        public abstract string Number { get; set; }
        public abstract decimal Balance { get; }

        internal void UpdateBalance(decimal delta)
        {
            SetProperty("Balance", Balance + delta);
        }
    }
    [Table]
    public abstract class Transaction : Entity
    {
        public abstract decimal Amount { get; set; }
        public abstract Account DebitAccount { get; set; }
        public abstract Account CreditAccount { get; set; }

        protected override void OnChanging(DataColumnChangeEventArgs e)
        {
            if (e.Column.ColumnName == "Amount" )
            {
                if (DebitAccount != null)
                    DebitAccount.UpdateBalance(+Amount);
                if (CreditAccount != null)
                    CreditAccount.UpdateBalance(-Amount);
            }

            if (e.Column.ColumnName == "DebitAccountID")
                if (DebitAccount != null)
                    DebitAccount.UpdateBalance(+Amount);

            if (e.Column.ColumnName == "CreditAccountID")
                if (CreditAccount != null)
                    CreditAccount.UpdateBalance(-Amount);

            base.OnChanging(e);
        }

        protected override void OnChanged(DataColumnChangeEventArgs e)
        {
            if (e.Column.ColumnName == "Amount")
            {
                if (DebitAccount != null)
                    DebitAccount.UpdateBalance(-Amount);
                if (CreditAccount != null)
                    CreditAccount.UpdateBalance(+Amount);
            }

            if (e.Column.ColumnName == "DebitAccountID")
                if (DebitAccount != null)
                    DebitAccount.UpdateBalance(-Amount);

            if (e.Column.ColumnName == "CreditAccountID")
                if (CreditAccount != null)
                    CreditAccount.UpdateBalance(+Amount);

            base.OnChanged(e);
        }
    }

    [Table]
    public abstract class Person : Entity
    {
        public abstract string Name { get; set;}
        public abstract IEntityList<Pet> Pets { get; }

        internal void OnPetAdded(Pet pet)
        {
            Console.WriteLine("Pet just added: " + pet.Name);
        }
    }

    [Table]
    public abstract class Pet : Entity
    {
        public abstract string Name { get; set;}
        public abstract Person Master { get; set; }

        protected override void OnChanged(DataColumnChangeEventArgs e)
        {
            if (e.Column.ColumnName == "MasterID")
                if (Master != null)
                    Master.OnPetAdded(this);

            base.OnChanged(e);
        }
    }


    [TestFixture]
    public class C09_Events
    {
        [TestBody]
        static void Main()
        {
            Session s = new Session();
            s.RegisterAssembly(Assembly.GetExecutingAssembly());
            s.Prepare();

            Person p = s.Create<Person>();
            Pet cat = s.Create<Pet>();
            cat.Name = "Molly";
            cat.Master = p;
            cat.Master = null;

            //Account a01 = s.Create<Account>();
            //Account a02 = s.Create<Account>();
            //Account a03 = s.Create<Account>();

            //Transaction t1 = s.Create<Transaction>();
            //t1.Amount = 100;
            //t1.DebitAccount = a01;
            //t1.CreditAccount = a02;
            //Transaction t2 = s.Create<Transaction>();
            //t2.Amount = 50;
            //t2.DebitAccount = a02;
            //t2.CreditAccount = a03;
            //Transaction t3 = s.Create<Transaction>();
            //t3.Amount = 10;
            //t3.DebitAccount = a03;
            //t3.CreditAccount = a01;

            //LUT.WriteLine("a01.Balance = {0}", a01.Balance);
            //LUT.WriteLine("a02.Balance = {0}", a02.Balance);
            //LUT.WriteLine("a03.Balance = {0}", a03.Balance);
        }

        [Test]
        public void Test()
        {
            LUT.Execute(Main);
        }
    }
}
